package org.xiaov.extra.jwt;

import io.jsonwebtoken.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.xiaov.config.autoconfigure.JWTProperties;
import org.xiaov.execption.XiaovAuthException;
import org.xiaov.execption.XiaovJwtException;
import org.xiaov.http.HttpCode;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.Date;
import java.util.Map;

/**
 * <p>
 * jwt的帮助类
 * </p>
 *
 * @author: xiaovcloud
 * @date: 2021/1/23 20:58
 */
@Component
public class JWTHelper {
    private static final Logger log = LoggerFactory.getLogger(JWTHelper.class);
    private static JWTProperties jwt;

    private static final String DEFAULT_SECRET_KEY = "1234567890!@#$%^&*";

    @Resource
    private JWTProperties jwtProperties;

    @PostConstruct
    public void init() {
        jwt = this.jwtProperties;

    }

    /**
     * 从token中获取claim
     *
     * @param token token
     * @return claim
     */
    public static Claims parseToken(String token) {
        try {
            return Jwts.parser()
                    .setSigningKey(jwt.getSecretKey())
                    .parseClaimsJws(token)
                    .getBody();
        } catch (ExpiredJwtException | UnsupportedJwtException | MalformedJwtException | IllegalArgumentException e) {
            log.error("token解析错误", e);
            throw new XiaovAuthException(HttpCode.HTTP_FORBIDDEN.getValue(), "token解析错误", e);
        } catch (Exception e) {
            log.error("非法的token异常", e);
            throw new XiaovAuthException(HttpCode.HTTP_FORBIDDEN.getValue(), "非法的token异常", e);
        }
    }

    /**
     * 从token中获取特定的值
     *
     * @param token
     * @param key
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T parseToken(String token, String key, Class<T> clazz) {
        Claims claims = parseToken(token);
        return claims.get(key, clazz);
    }

    /**
     * 获取token的过期时间
     *
     * @param token token
     * @return 过期时间
     */
    public static Date getExpirationDateFromToken(String token) {
        return parseToken(token).getExpiration();
    }

    /**
     * 判断token是否过期
     *
     * @param token token
     * @return 已过期返回true，未过期返回false
     */
    private static Boolean isTokenExpired(String token) {
        Date expiration = getExpirationDateFromToken(token);
        return expiration.before(new Date());
    }

    /**
     * 计算token的过期时间
     *
     * @return 过期时间
     */
    private static Date getExpirationTime() {
        return new Date(System.currentTimeMillis() + jwt.getExpireTime() * 1000);
    }

    /**
     * 为指定用户生成token
     *
     * @param claims 用户信息
     * @return token
     */
    public static String buildToken(Map<String, Object> claims) {
        //为了安全，必须使用加密，且私钥必须自己指定
        if (DEFAULT_SECRET_KEY.equals(jwt.getSecretKey())) {
            throw new XiaovJwtException("未指定key或使用了默认的key");
        }
        Date createTime = new Date();
        Date expirationTime = getExpirationTime();
        JwtBuilder builder = Jwts.builder()
                .setIssuedAt(createTime)
                .setExpiration(expirationTime)
                .setClaims(claims)
                .signWith(jwt.getSignature(), jwt.getSecretKey());

        if (jwt.getExpireTime() > 0) {
            builder.setExpiration(expirationTime);
        }
        return builder.compact();
    }

    /**
     * 判断token是否非法
     *
     * @param token token
     * @return 未过期返回true，否则返回false
     */
    public static Boolean validateToken(String token) {
        return !isTokenExpired(token);
    }

}
